#pragma once

#include <mcp/config.h>
#include <mcp/forward.h>
#include <mcp/types.h>
#include <mcp/error.h>

#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#include <optional>

namespace mcp {
namespace server {

/// @brief Prompt argument definition
struct PromptArgumentDefinition {
    std::string name;
    std::optional<std::string> description;
    bool required = false;
    std::optional<json::Schema> schema;

    PromptArgumentDefinition() = default;
    PromptArgumentDefinition(std::string name,
                           std::optional<std::string> description,
                           bool required,
                           std::optional<json::Schema> schema)
        : name(std::move(name))
        , description(std::move(description))
        , required(required)
        , schema(std::move(schema)) {}
};

/// @brief Prompt registration information
struct PromptRegistration {
    std::string name;
    std::optional<std::string> description;
    std::vector<PromptArgumentDefinition> arguments;
    std::function<Result<std::vector<types::PromptMessage>>(const json::Value&, Context<>&)> handler;

    PromptRegistration() = default;
    PromptRegistration(std::string name,
                      std::optional<std::string> description,
                      std::vector<PromptArgumentDefinition> arguments,
                      std::function<Result<std::vector<types::PromptMessage>>(const json::Value&, Context<>&)> handler)
        : name(std::move(name))
        , description(std::move(description))
        , arguments(std::move(arguments))
        , handler(std::move(handler)) {}
};

/// @brief Manager for MCP prompts
class PromptManager {
public:
    PromptManager();
    ~PromptManager();

    /// @brief Register a new prompt
    /// @param registration Prompt registration information
    /// @return true if registration succeeded, false if prompt already exists
    bool register_prompt(PromptRegistration registration);

    /// @brief Unregister a prompt
    /// @param name Prompt name to unregister
    /// @return true if unregistration succeeded, false if prompt not found
    bool unregister_prompt(const std::string& name);

    /// @brief Check if a prompt exists
    /// @param name Prompt name
    /// @return true if prompt exists, false otherwise
    bool has_prompt(const std::string& name) const;

    /// @brief Get all registered prompts
    /// @return List of prompt definitions
    std::vector<types::Prompt> list_prompts() const;

    /// @brief Get a specific prompt definition
    /// @param name Prompt name
    /// @return Prompt definition if found, std::nullopt otherwise
    std::optional<types::Prompt> get_prompt(const std::string& name) const;

    /// @brief Get prompt arguments
    /// @param name Prompt name
    /// @return Prompt arguments if found, std::nullopt otherwise
    std::optional<std::vector<PromptArgumentDefinition>> get_arguments(const std::string& name) const;

    /// @brief Call a prompt by name
    /// @param name Prompt name
    /// @param arguments Prompt arguments
    /// @param context MCP context for the call
    /// @return Prompt messages or error
    Result<std::vector<types::PromptMessage>> call_prompt(const std::string& name,
                                                           const json::Value& arguments,
                                                           Context<>& context);

    /// @brief Validate prompt arguments against schema
    /// @param name Prompt name
    /// @param arguments Arguments to validate
    /// @return Validation result
    json::ValidationResult validate_arguments(const std::string& name,
                                             const json::Value& arguments) const;

    /// @brief Build prompt definition from arguments
    /// @param arguments Prompt argument definitions
    /// @return Corresponding PromptArgument list for types::Prompt
    static std::vector<types::PromptArgument> build_prompt_arguments(
        const std::vector<PromptArgumentDefinition>& arguments);

    /// @brief Clear all registered prompts
    void clear();

private:
    struct Impl;
    std::unique_ptr<Impl> impl_;
};

} // namespace server
} // namespace mcp